home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 25 / AACD 25.iso / AACD / Utilities / BasiliskII / src / serial.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-02-02  |  6.4 KB  |  252 lines

  1. /*
  2.  *  serial.cpp - Serial device driver
  3.  *
  4.  *  Basilisk II (C) 1997-2001 Christian Bauer
  5.  *
  6.  *  This program is free software; you can redistribute it and/or modify
  7.  *  it under the terms of the GNU General Public License as published by
  8.  *  the Free Software Foundation; either version 2 of the License, or
  9.  *  (at your option) any later version.
  10.  *
  11.  *  This program is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *  GNU General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU General Public License
  17.  *  along with this program; if not, write to the Free Software
  18.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.  */
  20.  
  21. /*
  22.  *  SEE ALSO
  23.  *    Inside Macintosh: Devices, chapter 7 "Serial Driver"
  24.  *    Technote HW 04: "Break/CTS Device Driver Event Structure"
  25.  *    Technote 1018: "Understanding the SerialDMA Driver"
  26.  */
  27.  
  28. #include <stdio.h>
  29.  
  30. #include "sysdeps.h"
  31. #include "cpu_emulation.h"
  32. #include "main.h"
  33. #include "macos_util.h"
  34. #include "serial.h"
  35. #include "serial_defs.h"
  36.  
  37. #include "emul_op.h"
  38.  
  39. #define DEBUG 0
  40. #include "debug.h"
  41.  
  42.  
  43. // Global variables
  44. SERDPort *the_serd_port[2];
  45.  
  46.  
  47. /*
  48.  *  Driver Open() routine
  49.  */
  50.  
  51. int16 SerialOpen(uint32 pb, uint32 dce, int port)
  52. {
  53.     D(bug("SerialOpen port %d, pb %08lx, dce %08lx\n", port, pb, dce));
  54.  
  55.     if (port == 0 || port == 2) {
  56.  
  57.         // Do nothing for input side
  58.         return noErr;
  59.  
  60.     } else {
  61.  
  62.         // Do nothing if port is already open
  63.         SERDPort *the_port = the_serd_port[port >> 1];
  64.         if (the_port->is_open)
  65.             return noErr;
  66.  
  67.         // Init variables
  68.         the_port->read_pending = the_port->write_pending = false;
  69.         the_port->read_done = the_port->write_done = false;
  70.         the_port->cum_errors = 0;
  71.  
  72.         // Open port
  73.         int16 res = the_port->open(ReadMacInt16(0x1fc + (port & 2)));
  74.         if (res)
  75.             return res;
  76.  
  77.         // Allocate Deferred Task structures
  78.         M68kRegisters r;
  79.         r.d[0] = SIZEOF_serdt * 2;
  80.         Execute68kTrap(0xa71e, &r);        // NewPtrSysClear()
  81.         if (r.a[0] == 0) {
  82.             the_port->close();
  83.             return openErr;
  84.         }
  85.         uint32 input_dt = the_port->input_dt = r.a[0];
  86.         uint32 output_dt = the_port->output_dt = r.a[0] + SIZEOF_serdt;
  87.         D(bug(" input_dt %08lx, output_dt %08lx\n", input_dt, output_dt));
  88.  
  89.         WriteMacInt16(input_dt + qType, dtQType);
  90.         WriteMacInt32(input_dt + dtAddr, input_dt + serdtCode);
  91.         WriteMacInt32(input_dt + dtParam, input_dt + serdtResult);
  92.                                                             // Deferred function for signalling that Prime is complete (pointer to mydtResult in a1)
  93.         WriteMacInt16(input_dt + serdtCode, 0x2019);            // move.l    (a1)+,d0    (result)
  94.         WriteMacInt16(input_dt + serdtCode + 2, 0x2251);        // move.l    (a1),a1        (dce)
  95.         WriteMacInt32(input_dt + serdtCode + 4, 0x207808fc);    // move.l    JIODone,a0
  96.         WriteMacInt16(input_dt + serdtCode + 8, 0x4ed0);        // jmp        (a0)
  97.  
  98.         WriteMacInt16(output_dt + qType, dtQType);
  99.         WriteMacInt32(output_dt + dtAddr, output_dt + serdtCode);
  100.         WriteMacInt32(output_dt + dtParam, output_dt + serdtResult);
  101.                                                             // Deferred function for signalling that Prime is complete (pointer to mydtResult in a1)
  102.         WriteMacInt16(output_dt + serdtCode, 0x2019);            // move.l    (a1)+,d0    (result)
  103.         WriteMacInt16(output_dt + serdtCode + 2, 0x2251);        // move.l    (a1),a1        (dce)
  104.         WriteMacInt32(output_dt + serdtCode + 4, 0x207808fc);    // move.l    JIODone,a0
  105.         WriteMacInt16(output_dt + serdtCode + 8, 0x4ed0);        // jmp        (a0)
  106.  
  107.         the_port->is_open = true;
  108.         return noErr;
  109.     }
  110. }
  111.  
  112.  
  113. /*
  114.  *  Driver Prime() routine
  115.  */
  116.  
  117. int16 SerialPrime(uint32 pb, uint32 dce, int port)
  118. {
  119.     D(bug("SerialPrime port %d, pb %08lx, dce %08lx\n", port, pb, dce));
  120.  
  121.     // Error if port is not open
  122.     SERDPort *the_port = the_serd_port[port >> 1];
  123.     if (!the_port->is_open)
  124.         return notOpenErr;
  125.  
  126.     if (port == 0 || port == 2) {
  127.         if (the_port->read_pending) {
  128.             printf("FATAL: SerialPrimeIn() called while request is pending\n");
  129.             return readErr;
  130.         } else
  131.             return the_port->prime_in(pb, dce);
  132.     } else {
  133.         if (the_port->write_pending) {
  134.             printf("FATAL: SerialPrimeOut() called while request is pending\n");
  135.             return readErr;
  136.         } else
  137.             return the_port->prime_out(pb, dce);
  138.     }
  139. }
  140.  
  141.  
  142. /*
  143.  *  Driver Control() routine
  144.  */
  145.  
  146. int16 SerialControl(uint32 pb, uint32 dce, int port)
  147. {
  148.     uint16 code = ReadMacInt16(pb + csCode);
  149.     D(bug("SerialControl %d, port %d, pb %08lx, dce %08lx\n", code, port, pb, dce));
  150.  
  151.     // Error if port is not open
  152.     SERDPort *the_port = the_serd_port[port >> 1];
  153.     if (!the_port->is_open)
  154.         return notOpenErr;
  155.  
  156.     switch (code) {
  157.         case kSERDSetPollWrite:
  158.             return noErr;
  159.  
  160.         default:
  161.             return the_port->control(pb, dce, code);
  162.     }
  163. }
  164.  
  165.  
  166. /*
  167.  *  Driver Status() routine
  168.  */
  169.  
  170. int16 SerialStatus(uint32 pb, uint32 dce, int port)
  171. {
  172.     uint16 code = ReadMacInt16(pb + csCode);
  173.     D(bug("SerialStatus %d, port %d, pb %08lx, dce %08lx\n", code, port, pb, dce));
  174.  
  175.     // Error if port is not open
  176.     SERDPort *the_port = the_serd_port[port >> 1];
  177.     if (!the_port->is_open)
  178.         return notOpenErr;
  179.  
  180.     switch (code) {
  181.         case kSERDVersion:
  182.             WriteMacInt8(pb + csParam, 9);        // Second-generation SerialDMA driver
  183.             return noErr;
  184.  
  185.         case 0x8000:
  186.             WriteMacInt8(pb + csParam, 9);        // Second-generation SerialDMA driver
  187.             WriteMacInt16(pb + csParam + 4, 0x1997);    // Date of serial driver
  188.             WriteMacInt16(pb + csParam + 6, 0x0616);
  189.             return noErr;
  190.  
  191.         default:
  192.             return the_port->status(pb, dce, code);
  193.     }
  194. }
  195.  
  196.  
  197. /*
  198.  *  Driver Close() routine
  199.  */
  200.  
  201. int16 SerialClose(uint32 pb, uint32 dce, int port)
  202. {
  203.     D(bug("SerialClose port %d, pb %08lx, dce %08lx\n", port, pb, dce));
  204.  
  205.     if (port == 0 || port == 2) {
  206.  
  207.         // Do nothing for input side
  208.         return noErr;
  209.  
  210.     } else {
  211.  
  212.         // Close port if open
  213.         SERDPort *the_port = the_serd_port[port >> 1];
  214.         if (the_port->is_open) {
  215.             int16 res = the_port->close();
  216.             M68kRegisters r;                // Free Deferred Task structures
  217.             r.a[0] = the_port->input_dt;
  218.             Execute68kTrap(0xa01f, &r);        // DisposePtr()
  219.             the_port->is_open = false;
  220.             return res;
  221.         } else
  222.             return noErr;
  223.     }
  224. }
  225.  
  226.  
  227. /*
  228.  *  Serial interrupt - Prime command completed, activate deferred tasks to call IODone
  229.  */
  230.  
  231. static void serial_irq(SERDPort *p)
  232. {
  233.     if (p->is_open) {
  234.         if (p->read_pending && p->read_done) {
  235.             EnqueueMac(p->input_dt, 0xd92);
  236.             p->read_pending = p->read_done = false;
  237.         }
  238.         if (p->write_pending && p->write_done) {
  239.             EnqueueMac(p->output_dt, 0xd92);
  240.             p->write_pending = p->write_done = false;
  241.         }
  242.     }
  243. }
  244.  
  245. void SerialInterrupt(void)
  246. {
  247.     D(bug("SerialIRQ\n"));
  248.  
  249.     serial_irq(the_serd_port[0]);
  250.     serial_irq(the_serd_port[1]);
  251. }
  252.